/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.elcom.dailyexpress;

import com.elcom.util.BaseThreadFactory;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author GiangLT
 */
//BroadcastPool,BroadcastQueryPool,BscUpdaterPool,ZoneMappingPool
public class ExecutorManager {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private static ExecutorManager instance;
    private ConcurrentMap<String, ExecutorService> executorMap;

    private ExecutorManager() {
        executorMap = new ConcurrentHashMap<String, ExecutorService>();
        ThreadFactory threadFactory = new BaseThreadFactory("ExecutorManager", "ThreadPoolStatistic");
        ExecutorsMonitor executorsMonitor = new ExecutorsMonitor();
        Executors.newSingleThreadScheduledExecutor(threadFactory).scheduleAtFixedRate(executorsMonitor, 1, 1, TimeUnit.MINUTES);
    }

    public static synchronized ExecutorManager getInstance() {
        if (instance == null) {
            instance = new ExecutorManager();
        }

        return instance;
    }

    public synchronized ExecutorService addExecutor(String executorName, ExecutorService executor) {
        logger.debug("Adding executor {}", executorName);
        return executorMap.putIfAbsent(executorName, executor);
    }

    public synchronized ExecutorService updateExecutor(String executorName, ExecutorService executor) {
        logger.debug("Updating executor {}", executorName);
        return executorMap.put(executorName, executor);
    }

    public synchronized ExecutorService removeExecutor(String executorName) {
        logger.debug("Removing executor {}", executorName);
        return executorMap.remove(executorName);
    }

    public ExecutorService getExecutor(String executorName) {
        logger.debug("Returning executor {}", executorName);
        return executorMap.get(executorName);
    }

    public Set<Entry<String, ExecutorService>> getExecutors() {
        logger.debug("Returning all executors");
        return executorMap.entrySet();
    }

    private class ExecutorsMonitor implements Runnable {

        @Override
        public void run() {
            try {
                logPoolsInfo();
            } catch (Exception ex) {
                logger.error("", ex);
            }
        }

        private void logPoolsInfo() {
            Set<Map.Entry<String, ExecutorService>> executors = ExecutorManager.getInstance().getExecutors();
            for (Map.Entry<String, ExecutorService> entry : executors) {
                if (entry.getValue() instanceof ThreadPoolExecutor) {
                    ThreadPoolExecutor executor = (ThreadPoolExecutor) entry.getValue();
                    String poolName = entry.getKey();
                    int numOfThreadInPool = executor.getPoolSize();
                    int activeThreads = executor.getActiveCount();
                    long completedTaskCount = executor.getCompletedTaskCount();
                    long submittedTaskCount = executor.getTaskCount();
                    int queueSize = executor.getQueue().size();
                    int remainingQueueSize = executor.getQueue().remainingCapacity();
                    logger.debug("Pool: {} | ActiveThreads: {} | ThreadsInPool: {} | QueueSize: {} RemainingQueueSize: {} | SubmittedTasks: {}| CompletedTasks: {}",
                            new Object[]{poolName, activeThreads, numOfThreadInPool, queueSize, remainingQueueSize, submittedTaskCount, completedTaskCount});
                }
            }
        }
    }
}
